#include "ffmpegkits.h"
#include <QDebug>

extern "C" {
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
}

FFmpegKits::FFmpegKits(QObject *parent): QThread(parent), _isWorking(false)
{

}

void FFmpegKits::startPlay(QString url)
{
    _url = url;
    _isWorking = true;
    this->start(); // 开始运行耗时线程
}

void FFmpegKits::stopPlay()
{
    _isWorking = false;
    // this->quit(); // 由于重写的run函数中没有调用exec()开始事件循环，这里不需要调用quit()退出事件循环
}

void FFmpegKits::run()
{
    qDebug() << "FFmpegKits::run()...";

     // 初始化FFmpeg网络模块
    avformat_network_init();

    // 分配一个音视频封装格式上下文结构体AVFormatContext
    AVFormatContext *pFormatCtx = avformat_alloc_context();
    if (!pFormatCtx) {
        qCritical() << "Alloc avformat context failed.";
        return;
    }

    // 设置中断回调（重要！）由于av_read_frame是阻塞函数，当主线程将_isWorking置位false时，需要使用该中断唤醒av_read_frame
//    pFormatCtx->interrupt_callback.callback = [](void *ctx) -> int {
//        FFmpegKits *self = static_cast<FFmpegKits*>(ctx);
//        return !self->_isWorking; // 当 _isWorking 为false时返回1，表示中断
//    };
//    pFormatCtx->interrupt_callback.opaque = this;

    // 打开媒体文件并初始化媒体格式解析
    AVDictionary *avDict = nullptr; // 存储额外参数的字典
    av_dict_set(&avDict, "rtsp_transport", "udp", 0);
    av_dict_set(&avDict, "max_delay", "100", 0);
    int ret = avformat_open_input(&pFormatCtx, _url.toStdString().c_str(), nullptr, &avDict);
    if (ret != 0) {
        qCritical() << "Open file failed.";
        avformat_free_context(pFormatCtx);
        return;
    }

    // 解析输入文件流信息
    ret = avformat_find_stream_info(pFormatCtx, nullptr);
    if (ret < 0) {
        qWarning() << "Find stream information failed.";
        avformat_close_input(&pFormatCtx); // 此次必须保证pFormatCtx不为nullptr
//        avformat_free_context(pFormatCtx); // avformat_close_input会关闭打开的文件流并释放AVFormatContext结构体，此行不需要，否则会重复释放
        return;
    }
    qDebug() << "pFormatCtx->nb_streams:" << pFormatCtx->nb_streams;

    // 查找视频中包含的流信息（音频流先不处理）
    int videoStreamIdx = av_find_best_stream(pFormatCtx, AVMEDIA_TYPE_VIDEO, -1, -1, nullptr, 0);
    if (videoStreamIdx < 0) {
        qCritical() << "av_find_best_stream error:" << av_get_media_type_string(AVMEDIA_TYPE_VIDEO);
        avformat_close_input(&pFormatCtx);
        return;
    }
    qDebug() << "video stream idx:" << videoStreamIdx;

    // 查找音视频解码器
    qDebug() << "avcodec_find_decoder...";
    enum AVCodecID id = pFormatCtx->streams[videoStreamIdx]->codecpar->codec_id;
    qDebug() << "AVCodecID:" << id;
    AVCodec *pCodec = avcodec_find_decoder(id);
    if (!pCodec) {
        qCritical() << "Codec not found.";
        avformat_close_input(&pFormatCtx);
        return;
    }

    // 为解码器分配一个音视频编解码器上下文结构体AVCodeContext
    AVCodecContext *pCodecCtx = avcodec_alloc_context3(pCodec);
    // 拷贝解码器参数
    avcodec_parameters_to_context(pCodecCtx, pFormatCtx->streams[videoStreamIdx]->codecpar);
    qDebug() << "pCodecCtx->codec_id:" << pCodecCtx->codec_id;
    // 初始化解码器参数
    pCodecCtx->bit_rate = 0; // 平均码率
    pCodecCtx->time_base.num = 1; // 时间基（每个时间刻度的秒数）分子
    pCodecCtx->time_base.den = 25; // 时间基分母
    pCodecCtx->frame_number = 1; // 每个包的视频帧数

    // 打开解码器
    ret = avcodec_open2(pCodecCtx, pCodec, nullptr);
    if (ret < 0) {
        qCritical() << "Open codec failed.";
        avcodec_free_context(&pCodecCtx);
        avformat_close_input(&pFormatCtx);
        return;
    }

    // 将解码后的YUV数据转换为RGB32
    // 创建并配置图像转换上下文结构体
    struct SwsContext *pImgConvertCtx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt,
                                                            pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_RGB32,
                                                            SWS_BICUBIC, nullptr, nullptr, nullptr);

    // 准备源和目标数据缓冲区
    int numBytes = avpicture_get_size(AV_PIX_FMT_RGB32, pCodecCtx->width, pCodecCtx->height);
    AVFrame *pFrame = av_frame_alloc();
    AVFrame *pFrameRGB = av_frame_alloc();
    uint8_t *pOutBuffer = (uint8_t *)av_malloc(numBytes * sizeof(uint8_t));
    avpicture_fill((AVPicture *)pFrameRGB, pOutBuffer, AV_PIX_FMT_RGB32, pCodecCtx->width, pCodecCtx->height);
    AVPacket *pPacket = av_packet_alloc(); // 分配一个Packet
    int y_size = pCodecCtx->width * pCodecCtx->height;
    av_new_packet(pPacket, y_size); // 分配Packet的数据

    while(_isWorking) {
        ret = av_read_frame(pFormatCtx, pPacket);
        if (ret < 0) {
            if (ret == AVERROR_EOF || ret == AVERROR(EINTR)) { // 视频流读完了或发生中断（_isWorking被置为false）
                qDebug() << "Stream ended or interrupted";
            }
            else {
                qCritical() << "av_read_frame error.";
            }
            break;
        }
        // 只处理视频流
        if (pPacket->stream_index == videoStreamIdx) {
            // 执行解码
#if 0
            int got_picture;
            ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, pPacket);
            if (ret < 0) {
                qCritical() << "Decode error.";
                break;
            }
            if (got_picture) {
                // 执行转换
                sws_scale(pImgConvertCtx, (uint8_t const * const *)pFrame->data, pFrame->linesize, 0,
                          pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize);
                // 使用QImage加载该RGB数据
                QImage tmpImg((uchar *)pOutBuffer, pCodecCtx->width, pCodecCtx->height, QImage::Format_RGB32);
                // 复制一份图像传给界面显示
                QImage image = tmpImg.copy();
                emit sigGetOneFrame(image); // 发送信号
            }
        av_free_packet(pPacket);
    }
#endif
            // 发送包到解码器
            ret = avcodec_send_packet(pCodecCtx, pPacket);
            if (ret < 0) {
                qWarning() << "Send packet to decoder failed.";
                av_packet_unref(pPacket);
                continue;
            }

            // 接收解码后的帧
            while (ret >= 0) {
                ret = avcodec_receive_frame(pCodecCtx, pFrame);
                if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
                    break;
                }
                else if (ret < 0) {
                    qWarning() << "Receive frame from decoder failed.";
                    break;
                }

                // 转换帧格式
                sws_scale(pImgConvertCtx, pFrame->data, pFrame->linesize, 0,
                          pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize);

                // 使用QImage加载该RGB数据
                QImage tmpImg(pOutBuffer, pCodecCtx->width, pCodecCtx->height, QImage::Format_RGB32);
                // 复制一份图像传给界面显示
                QImage image = tmpImg.copy();
                emit sigGetOneFrame(image); // 发送信号

                av_frame_unref(pFrame);
            }
        }
        av_packet_unref(pPacket); // 将AVPacket结构体重置为初始状态，同时释放其内部引⽤的数据缓冲区
    }
    if (pPacket) {
        av_packet_free(&pPacket);
    }
    sws_freeContext(pImgConvertCtx);
    av_free(pOutBuffer);
    av_frame_free(&pFrameRGB);
    av_frame_free(&pFrame);
    avcodec_free_context(&pCodecCtx);
    avformat_close_input(&pFormatCtx);
    avformat_network_deinit();
    qDebug() << "FFmpeg::run() finished.";
}
